#!/usr/bin/perl
use strict;
use warnings;

use Data::Dumper;
use Digest::SHA1 qw(sha1_hex);
use FileHandle;
use Fcntl ':flock';    # import LOCK_* constants
use Mail::POP3Client;
use Contact;
use Contact::Manager;

my $self_fh;

if ( !lockself() ) {
    exit;
}

my $rv
    = initNetPop3(
    { 'hostname' => 'pop.gmail.com', 'ssl' => 1, 'username' => 'broadcast@ocfconvention.org', 'password' => '797P53' }
    );
if ( $rv->{'pop'} ) {
    my $msg = getOnePop3Message( { 'pop' => $rv->{'pop'} } );
    $rv->{'pop'}->Close();

    if ( $msg && scalar($msg) ) {
        $msg = filterHeadersFromMessage(
            {   'permitted_headers' =>
                    [ 'From', 'To', 'Content-Type', 'Content-Transfer-Encoding', 'Mime-Version', 'Subject', 'Date' ],
                'message' => $msg
            }
        );
        my $contacts = Contact::Manager->get_contacts();
        foreach my $contact (@$contacts) {
            if (!$contact->active) {
                next;
            }
            $msg = preprocessHeadersFromMessage( { 'message' => $msg } );
            my $replacements = buildReplacementsFromObject( { 'object' => $contact } );
            my $new_msg = replaceVariablesInMessage( { 'message' => $msg, 'replacements' => $replacements } );

            if ( !insertIntoMailQueue( $contact->email, @$new_msg ) ) {
                warn "Error creating mail queue for " . $contact->email;
            }
        } ## end foreach my $contact (@$contacts)
    } ## end if ( $msg && scalar($msg) )
} ## end if ( $rv->{'pop'} )

sub lockself {
    my $scriptfile = $0;
    $self_fh = new FileHandle $scriptfile, "r";
    my $rv = flock( $self_fh, LOCK_EX | LOCK_NB );
    return $rv;
} ## end sub lockself

sub initNetPop3 {
    my $params = shift || {};

    # initialise method variables
    my $hostname = $params->{'hostname'};
    my $username = $params->{'username'};
    my $password = $params->{'password'};
    my $ssl      = $params->{'ssl'};

    my $pop;
    my $rv = {};
    $pop = new Mail::POP3Client(
        'HOST'     => $hostname,
        'USER'     => $username,
        'PASSWORD' => $password,
        'USESSL'   => $ssl,
        DEBUG      => 0
    );

    if ( ( $rv->{'result'} = $pop->Count() ) > 0 ) {
        $rv->{'pop'} = $pop;
    }
    return $rv;
} ## end sub initNetPop3

sub getOnePop3Message {
    my $params = shift || {};

    my $pop = $params->{'pop'};
    my $index = $params->{'index'} || 1;

    if ( $pop && $pop->Count() ) {
        my @msgcontent = $pop->HeadAndBody($index);

        $pop->Delete($index);

        return \@msgcontent;    # only one mail returned
    } ## end if ( $pop && $pop->Count() )
} ## end sub getOnePop3Message

sub filterHeadersFromMessage {
    my $params = shift || {};

    my $permitted_headers = $params->{'permitted_headers'};
    my $msg               = $params->{'message'};
    my $rv                = [];

    my $scope_header;
    my $headers_end;
    my $permitted_headers_hash = {};

    # build lookup hash for permitted headers
    foreach my $permitted_header (@$permitted_headers) {
        $permitted_headers_hash->{ lc($permitted_header) } = 1;
    }

    # begins processing message
    foreach my $msgline (@$msg) {
        my $new_msgline = $msgline;
        if ( $new_msgline =~ /^([\S]+):/ ) {
            $scope_header = $1;
        }
        elsif ( $new_msgline =~ /^\s+/ ) {

            # multiline header
        }
        elsif ( $new_msgline =~ /^$/ ) {
            $headers_end = 1;
        }

        if ( exists( $permitted_headers_hash->{ lc($scope_header) } ) || $headers_end ) {
            push @$rv, $new_msgline;
        }
    } ## end foreach my $msgline (@$msg)
    return $rv;
} ## end sub filterHeadersFromMessage

sub preprocessHeadersFromMessage {
    my $params = shift || {};

    my $msg = $params->{'message'};
    my $rv  = [];

    my $scope_header;
    my $headers_end;

    # begins processing message
    foreach my $msgline (@$msg) {
        my $new_msgline = $msgline;
        if ( $new_msgline =~ /^([\S]+):/ ) {
            $scope_header = $1;
        }
        elsif ( $new_msgline =~ /^\s+/ ) {

            # multiline header
        }
        elsif ( $new_msgline =~ /^$/ ) {
            $headers_end = 1;
        }
        if ( lc($scope_header) eq 'to' && !$headers_end ) {
            $new_msgline = "$scope_header: [name] <[email]>";
        }
        elsif ( lc($scope_header) eq 'from' && !$headers_end ) {

        }

        push @$rv, $new_msgline;
    } ## end foreach my $msgline (@$msg)
    return $rv;
} ## end sub preprocessHeadersFromMessage

sub buildReplacementsFromObject {
    my $params = shift || {};

    my $obj = $params->{'object'};    # Rose::DB::Object object
    if ($obj) {
        my $columns;
        my $replacements = {};
        $columns = $obj->meta->columns;

        foreach my $column (@$columns) {
            $replacements->{$column} = $obj->$column();
        }
        return $replacements;
    } ## end if ($obj)
} ## end sub buildReplacementsFromObject

sub replaceVariablesInMessage {
    my $params = shift || {};

    my $msg = $params->{'message'};
    my $replacements = $params->{'replacements'} || {};

    my $rv = [];

    if ( defined($msg) && ( ref($msg) eq 'ARRAY' ) ) {
        foreach my $line (@$msg) {
            my $new_line = $line;
            while ( $new_line =~ /\[([a-z0-9\_]+)\]/
                && defined( my $replacement = $replacements->{ ( my $token = $1 ) } ) )
            {
                $new_line =~ s/\[$token\]/$replacement/g;
            }
            push @$rv, $new_line;
        } ## end foreach my $line (@$msg)
        return $rv;
    } ## end if ( defined($msg) && ( ref($msg) eq 'ARRAY'...
} ## end sub replaceVariablesInMessage

sub insertIntoMailQueue {
    my $to            = shift;
    my @data          = @_;
    my $filename_base = Digest::SHA1::sha1_hex( lc( join( "\n", $to, @data ) ) );
    my $filename = '/home/woeishya/domains/ocfaustralia.org/connect/public_html/cgi-bin/mailqueue/' . $filename_base;

    my $fh = new FileHandle $filename, "w";
    if ( defined($fh) ) {
        print $fh join( "\n", $to, @data );
        $fh->close;
        return 1;
    }
} ## end sub insertIntoMailQueue
